luachip.sunpack = function(tab,s,e)
	local extracted = {}
	for i=s,e do
		table.insert(extracted,tab[i])
	end
	
	return unpack(extracted)
end

luachip.isValidPhrase = function(phrasecode,i,globals,ignore)
	local phrase = phrasecode[i]
	if luachip.isExpressionModifier(phrase) then
		Msg("\t\tPassed test 1 (Expression modifier)\n")
	elseif luachip.isLibraryVar(phrase) then
		Msg("\t\tPassed test 2 (Library variable)\n")
	elseif luachip.isLocalVar(phrase) then
		globals[phrase] = "variable"
		Msg("\t\tPassed test 3 (User variable)\n")
	elseif luachip.isValidString(phrase) then
		Msg("\t\tPassed test 4 (String)\n")
	elseif tonumber(phrase) and phrasecode[i+1] == "." and tonumber(phrasecode[i+2]) then
		phrasecode[i] = phrase .. phrasecode[i+1] .. phrasecode[i+2]
		ignore[i+1] = true
		ignore[i+2] = true
		phrasecode[i+1] = ""
		phrasecode[i+2] = ""
		Msg("\t\tPassed test 5 (Float)\n")
	elseif tonumber(phrase) then
		Msg("\t\tPassed test 6 (Number)\n")
	elseif luachip.isTableOperator(phrase) then
		Msg("\t\tPassed test 7 (Table Operator)\n")
	elseif phrase == "..." then
		Msg("\t\tPassed test 8 (Elipsis)\n")
	elseif luachip.isOperator(phrase) then
		Msg("\t\tPassed test 9 (Operator)\n")
	elseif luachip.isKeyword(phrase) then
		Msg("\t\tPassed test 10 (Is keyword)\n")
	else
		Msg("[ERROR] Did not pass phrase restrictions (",i,")\n")
		return false
	end
	return true
end

luachip.isLocalVar = function(str)
	//The str must start with a letter, be alphanumeric, and not be a keyword
	if str == "" or luachip.isKeyword(str) or (not luachip.charIsAlpha(str:sub(1,1))) or luachip.isReservedVar(str) or not luachip.strIsAlphaNumeric(str) then
		return false
	end
	return true
end

luachip.isValidString = function(str)
	local op = str:sub(1,1)
	
	if not luachip.isStringOperator(op) then
		return false
	end
	
	local lc = str:sub(#str)
	if not op == lc then
		//M/sg(op," ~= ",lc,"\n")
		return false
	end
	
	//There is no escape. Muhahahahahhahahahahahhahahahhahahahhahahaha*ECH*...ow...
	if #str > #op*2 then
		if str:sub(#str-#op,#str-#op) == "\\" then
			return false
		end
	elseif #str > #op*2+1 then
		if str:sub(#str-#op,#str-#op) == "\\" and str:sub(#str-#op-1,#str-#op-1) ~= "\\" then
			return false
		end
	end
	
	return true
end

luachip.find = function(phrasecode,pS,pE,phrase)
	//I KEEP FORGETTING THE FOLLOWING:
	//Strings are always parsed before calling this, so there is NO NEED to check if a phrase occurs within quotes
	//BTW: Strings are saved as phrases WITH the operatorS (plural), and because no keywords use ", ', [[, or ]], there is no possibility of exploitation here
	
	for i=pS,pE do
		if phrase == phrasecode[i] then //This is an equality, the actual phrase is NOT searched
			return i
		end
	end
	return false
end

luachip.findExpressionTerminus = function(phrasecode,pS,pE,list)
	local lastOp = true
	for i=pS,pE do
		local phrase = phrasecode[i]
		local op = nil
		
		if luachip.isExpressionOperator(phrase) or (list and phrase == ",") then
			op = true
		else
			op = false
		end
		Msg("\tOPCHECK [",i,"] ",op,"\n")
		
		if lastOp == op then
			return i-1
		end
	end
	return false
end

luachip.isExpressionModifier = function(phrase)
	if luachip.isExpressionOperator(phrase) or luachip.isNegationOperator(phrase) or luachip.isExpressionKeyword(phrase) then
		return true
	end
	return false
end

//This is used for matching string operators
luachip.matchPairRaw = function(phrasecode,pS,pE,cS,cE,ignore,reverse)
	local match = {}
	local cE = cE or cS
	local toggle = false
	if cE == cS then
		toggle = true
		match = nil
	end
	
	Msg("//MATCHPAIR: ",pS,":",pE," .. ",cS,":",cE,"\n")
	
	local ignore = ignore or {}
	
	local a,b,c
	if reverse then
		a,b,c = pS,pE,1
	else
		a,b,c = pE,pS,-1
	end
	
	for i=a,b,c do
		if not ignore[i] then
			local char = phrasecode[i]
			
			if toggle then
				if char == (reverse and cS or cE) then
					if match then
						if i == (reverse and pE or pS) then
							return match
						end
						match = nil
					else
						match = i
					end
				end
			else
				if char == (reverse and cS or cE) then
					table.insert(match,i)
				elseif char == (reverse and cE or cS) then
					if #match > 0 then
						local a = table.remove(match)
						if i == (reverse and pE or pS) then
							if #match > 0 then
								return a //false //Missing a brace!
							else
								return a
							end
						end
					end
				end
			end
		end
	end
	
	return false //Missing something...
end

//This is used for matching non-string operators
luachip.matchPair = function(phrasecode,pS,pE,cS,cE,ignore,reverse)
	// '
	// "
	// [[ and ]]
	
	local ignore = ignore or {}
	
	local a,b,c
	if reverse then
		a,b,c = pE,pS,-1
	else
		a,b,c = pS,pE,1
	end
	
	for i=a,b,c do
	//for i=pE,pS,-1 do
		for k,v in pairs{
			"'",
			'"',
			{
				"[[",
				"]]",
			}
		} do
			if not ignore[i] then
				local dS,dE
				if type(v) == "string" then
					dS,dE = v,v
				else
					dS,dE = unpack(v)
				end
				if reverse and phrasecode[i] == dE then
					local s = luachip.matchPairRaw(phrasecode,pS,i,dS,dE,ignore,reverse)
					if s then
						for bad=s,i do
							ignore[bad] = true
						end
					else
						return false //We have an unmatched brace
					end
				elseif (not reverse) and phrasecode[i] == dS then
					local s = luachip.matchPairRaw(phrasecode,i,pE,dS,dE,ignore,reverse)
					if s then
						for bad=i,s do
							ignore[bad] = true
						end
					else
						return false //We have an unmatched brace
					end
				end
			end
		end
	end
	
	return luachip.matchPairRaw(phrasecode,pS,pE,cS,cE,ignore,reverse)
end


















